package actor

import (
	"log"
	"reflect"
	"sync"

	sadefine "gitee.com/simplexyz/simplego/actor/define"
	sdefine "gitee.com/simplexyz/simplego/define"
	slog "gitee.com/simplexyz/simplego/log"
)

type option struct {
	startedWg *sync.WaitGroup
	stoppedWg *sync.WaitGroup

	mailBoxSize int

	decider sadefine.DeciderFunc

	onStartedFuncs    []sdefine.OnActorStartedFunc
	onStoppingFuncs   []sdefine.OnActorStoppingFunc
	onStoppedFuncs    []sdefine.OnActorStoppedFunc
	onRestartingFuncs []sdefine.OnActorRestartingFunc
	onTerminatedFuncs []sdefine.OnActorTerminatedFunc

	beforeTriggerTimerFuncs []sdefine.BeforeActorTriggerTimerFunc
	afterTriggerTimerFuncs  []sdefine.AfterActorTriggerTimerFunc

	onReceiveMessageFuncs map[reflect.Type][]sdefine.OnActorReceiveMessageFunc

	name string

	logger slog.ILogger
}

func (o *option) destroy() {
	clear(o.onStartedFuncs)
	clear(o.onStoppingFuncs)
	clear(o.onStoppedFuncs)
	clear(o.onTerminatedFuncs)
	clear(o.onRestartingFuncs)

	clear(o.beforeTriggerTimerFuncs)
	clear(o.afterTriggerTimerFuncs)

	clear(o.onReceiveMessageFuncs)

	o.decider = nil

	//o.startedWg = nil

	o.stoppedWg = nil
}

type OptionFunc func(option *option)

func createOption() *option {
	return &option{
		onReceiveMessageFuncs: make(map[reflect.Type][]sdefine.OnActorReceiveMessageFunc),
	}
}

func WithStartedWaitGroup(startedWg *sync.WaitGroup) OptionFunc {
	return func(option *option) {
		option.startedWg = startedWg
	}
}

func WithStoppedWaitGroup(stoppedWg *sync.WaitGroup) OptionFunc {
	return func(option *option) {
		option.stoppedWg = stoppedWg
	}
}

func WithMailBoxSize(mailBoxSize int) OptionFunc {
	return func(option *option) {
		if mailBoxSize > 0 {
			option.mailBoxSize = mailBoxSize
		}
	}
}

func WithDecider(decider sadefine.DeciderFunc) OptionFunc {
	return func(option *option) {
		if decider != nil {
			option.decider = decider
		}
	}
}

func WithOnStartedFunc(funcs ...sdefine.OnActorStartedFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.onStartedFuncs = append(option.onStartedFuncs, f)
			}
		}
	}
}

func WithOnStoppingFunc(funcs ...sdefine.OnActorStoppingFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.onStoppingFuncs = append(option.onStoppingFuncs, f)
			}
		}
	}
}

func WithOnStoppedFunc(funcs ...sdefine.OnActorStoppedFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.onStoppedFuncs = append(option.onStoppedFuncs, f)
			}
		}
	}
}

func WithOnRestartingFunc(funcs ...sdefine.OnActorRestartingFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.onRestartingFuncs = append(option.onRestartingFuncs, f)
			}
		}
	}
}

func WithOnTerminatedFunc(funcs ...sdefine.OnActorTerminatedFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.onTerminatedFuncs = append(option.onTerminatedFuncs, f)
			}
		}
	}
}

func WithBeforeTriggerTimerFunc(funcs ...sdefine.BeforeActorTriggerTimerFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.beforeTriggerTimerFuncs = append(option.beforeTriggerTimerFuncs, f)
			}
		}
	}
}

func WithAfterTriggerTimerFunc(funcs ...sdefine.AfterActorTriggerTimerFunc) OptionFunc {
	return func(option *option) {
		for _, f := range funcs {
			if f != nil {
				option.afterTriggerTimerFuncs = append(option.afterTriggerTimerFuncs, f)
			}
		}
	}
}

func WithOnReceiveMessageFunc(t reflect.Type, funcs ...sdefine.OnActorReceiveMessageFunc) OptionFunc {
	return func(option *option) {
		if len(funcs) == 0 {
			log.Printf("WithOnReceiveMessageFunc len(funcs) == 0")
			return
		}

		_, ok := option.onReceiveMessageFuncs[t]
		if ok {
			log.Printf("WithOnReceiveMessageFunc message[%v] already register", t)
			return
		}

		option.onReceiveMessageFuncs[t] = funcs
	}
}

func WithName(name string) OptionFunc {
	return func(option *option) {
		option.name = name
	}
}

func WithLogger(logger slog.ILogger) OptionFunc {
	return func(option *option) {
		option.logger = logger
	}
}
